package com.guuidea.nio.chat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

public class ChatServer {

    private ServerSocketChannel listenerChanel; //监听通道 老大
    private Selector selector; //选择器对象 间谍

    private static final int PORT = 9999;

    public ChatServer() {
        try {

            //1 得到监听通道 老大
            listenerChanel = ServerSocketChannel.open();

            //2 得到选择器 间谍
            selector = Selector.open();

            //3 绑定端口
            listenerChanel.bind(new InetSocketAddress(PORT));

            //4 设置为非阻塞模式
            listenerChanel.configureBlocking(false);

            //5 将选择器绑定到监听通道并监听 accept事件

            listenerChanel.register(selector, SelectionKey.OP_ACCEPT);

            printInfo("Chat Server is ready");

        } catch (IOException e) {
            e.printStackTrace();

        }

    }

    //6 干活
    public void start() {
        try {
            while (true) {
                //6.1 监控客户端
                if (selector.select(2000) == 0) {
                    //nio 非阻塞式的优势
                    System.out.println("Server:没有客户端搭理我,我就干点别的事儿");
                    continue;
                }
                //6.2 得到SelectionKey 判断通道里的事件
                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    //客户端连接请求事件
                    if (key.isAcceptable()) {
                        toLinked(listenerChanel);
                    }
                    //读取客户端数据事件
                    if (key.isReadable()) {
                        readMsg(key);
                    }
                    //6 3  手动从集合中移除当前的key 防止重复处理
                    keyIterator.remove();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 初始化 连接
     *
     * @param listenerChanel
     * @throws IOException
     */
    private void toLinked(ServerSocketChannel listenerChanel) throws IOException {
        System.out.println("OP_ACCEPT");
        SocketChannel sc = listenerChanel.accept();
        sc.configureBlocking(false);
        sc.register(selector, SelectionKey.OP_READ);
        System.out.println(sc.getRemoteAddress().toString().substring(1) + "上线了....");
    }

    /**
     * 读取客户端发来的消息并广播出去
     *
     * @param key
     * @throws IOException
     */
    private void readMsg(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int count = channel.read(buffer);
        if (count > 0) {
            String msg = new String(buffer.array());
            printInfo(msg);
            broadCast(msg, channel);
        }

    }

    /**
     * 给所有的 客户端 发起广播
     *
     * @param msg
     * @param channel
     */
    private void broadCast(String msg, SocketChannel except) throws IOException {
        System.out.println("服务器发送了广播...");

        //获取已经连接的 对象
        for (SelectionKey key : selector.keys()) {
            SocketChannel targetChannel = (SocketChannel) key.channel();
            if (targetChannel instanceof SocketChannel && targetChannel != except) {
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                targetChannel.write(buffer);
            }
        }


    }

    /**
     * 答应消息
     *
     * @param str
     */
    private void printInfo(String str) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("[" + sdf.format(new Date()) + "]->" + str);
    }

}
